package cn.tqfeiyang.springplus.framework.security;

import cn.tqfeiyang.springplus.framework.conversion.ConversionService;
import cn.tqfeiyang.springplus.framework.logging.LoggingRequirement;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import cn.tqfeiyang.springplus.framework.Constants;
import cn.tqfeiyang.springplus.framework.response.ApiResult;

import jakarta.servlet.http.HttpServletRequest;

/**
 * 授权管理
 *
 * @author tqfeiyang
 * @since 2024-07-19
 */
@RestController
@Tag(name = "公共/授权")
public class AuthenticationController {

    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private JwtTokenService jwtTokenService;

    @Resource
    private SecurityService securityService;

    @Resource
    private ConversionService conversionService;

    /**
     * 用户登录
     *
     * @return 登录结果
     */
    @PostMapping(value = Constants.AUTH_LOGIN_URL)
    @Operation(summary = "用户登录")
    @LoggingRequirement
    public ApiResult<LoginVO> login(@RequestBody @Validated LoginDTO loginDTO) {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword()));
        AuthenticationUserDetails userDetails = (AuthenticationUserDetails) authentication.getPrincipal();
        return ApiResult.success(new LoginVO(jwtTokenService.build(userDetails)));
    }

    /**
     * 用户登出
     *
     * @return 登出结果
     */
    @PostMapping(Constants.AUTH_LOGOUT_URL)
    @Operation(summary = "用户登出")
    @JwtSecurityRequirement
    @LoggingRequirement
    public ApiResult logout() {
        return ApiResult.success();
    }

    /**
     * token刷新
     *
     * @return 刷新结果
     */
    @PostMapping(Constants.AUTH_REFRESH_URL)
    @Operation(summary = "token刷新")
    @JwtSecurityRequirement
    @LoggingRequirement
    public ApiResult<LoginVO> refresh(HttpServletRequest httpRequest) {
        JwtTokenSubject subject = (JwtTokenSubject) httpRequest.getAttribute(Constants.AUTH_SUBJECT_ATTR);
        return ApiResult.success(new LoginVO(jwtTokenService.build(subject)));
    }

    /**
     * 获取用户信息
     *
     * @return 用户信息
     */
    @GetMapping(Constants.AUTH_INFO_URL)
    @Operation(summary = "获取用户信息")
    @JwtSecurityRequirement
    @LoggingRequirement
    public ApiResult<UserVO> info() {
        AuthenticationUserDetails userDetails = securityService.getCurrentUser();
        UserVO userVO = conversionService.map(userDetails, UserVO.class);
        return ApiResult.success(userVO);
    }

    /**
     * 登录信息
     */
    @Data
    @Schema(description = "登录信息")
    public static class LoginDTO {
        @Schema(description = "用户名")
        @NotBlank(message = "用户名不能为空")
        private String username;

        @Schema(description = "密码")
        @NotBlank(message = "密码不能为空")
        private String password;
    }

    /**
     * 用户token
     */
    @Data
    @AllArgsConstructor
    @Schema(description = "token信息")
    public static class LoginVO {
        @Schema(description = "token")
        private String token;
    }

    /**
     * 用户信息
     */
    @Data
    @Schema(description = "用户信息")
    public static class UserVO {
        @Schema(description = "UUID")
        private String uuid;

        @Schema(description = "用户ID")
        private Long id;

        @Schema(description = "用户名")
        private String username;

        @Schema(description = "状态")
        private boolean enabled;

        @Schema(description = "昵称")
        private String nickname;

        @Schema(description = "头像")
        private String avatar;

        @Schema(description = "简介")
        private String introduction;
    }

}
